﻿using System;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace HDM.NexusEngine.Editor
{

    public class ListViewEx : ListView
    {
        private const string REORDER = "Reorder";
        private bool _allowRowReorder = true;

        public bool AllowRowReorder
        {
            get { return _allowRowReorder; }
            set
            {
                _allowRowReorder = value;
                base.AllowDrop = value;
            }
        }

        public new SortOrder Sorting
        {
            get { return SortOrder.None; }
            set { base.Sorting = SortOrder.None; }
        }

        public ListViewEx()
        {
            AllowRowReorder = true;
        }

        protected override void OnDragDrop(DragEventArgs e)
        {
            base.OnDragDrop(e);

            if (!AllowRowReorder) return;
            if (SelectedItems.Count == 0) return;

            var cp = PointToClient(new Point(e.X, e.Y));
            var dragToItem = GetItemAt(cp.X, cp.Y);

            if (dragToItem == null) return;

            var dropIndex = dragToItem.Index;

            if (dropIndex > SelectedItems[0].Index) dropIndex++;

            var insertItems = new ArrayList(SelectedItems.Count);

            foreach (ListViewItem item in SelectedItems)
            {
                insertItems.Add(item.Clone());
            }

            for (var i = insertItems.Count - 1; i >= 0; i--)
            {
                var insertItem = (ListViewItem)insertItems[i];
                Items.Insert(dropIndex, insertItem);
            }

            foreach (ListViewItem removeItem in SelectedItems)
            {
                Items.Remove(removeItem);
            }
        }

        protected override void OnDragOver(DragEventArgs e)
        {
            if (!AllowRowReorder)
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            var cp = PointToClient(new Point(e.X, e.Y));
            var hoverItem = GetItemAt(cp.X, cp.Y);

            if (hoverItem == null)
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            if (SelectedItems.Cast<ListViewItem>().Any(moveItem => moveItem.Index == hoverItem.Index))
            {
                e.Effect = DragDropEffects.None;
                hoverItem.EnsureVisible();
                return;
            }

            base.OnDragOver(e);

            var text = (String)e.Data.GetData(REORDER.GetType());

            if (String.Compare(text, REORDER, StringComparison.Ordinal) == 0)
            {
                e.Effect = DragDropEffects.Move;
                hoverItem.EnsureVisible();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        protected override void OnDragEnter(DragEventArgs e)
        {
            base.OnDragEnter(e);

            if (!AllowRowReorder)
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            base.OnDragEnter(e);

            var text = (String)e.Data.GetData(REORDER.GetType());

            e.Effect = String.Compare(text, REORDER, StringComparison.Ordinal) == 0 ? DragDropEffects.Move : DragDropEffects.None;
        }

        protected override void OnItemDrag(ItemDragEventArgs e)
        {
            base.OnItemDrag(e);
            if (!AllowRowReorder) return;
            DoDragDrop(REORDER, DragDropEffects.Move);
        }
    }
}